package com.asimplefox.filter;

import com.asimplefox.entity.Visitor;
import com.asimplefox.service.IVisitorService;
import com.asimplefox.service.abst.ResultU;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.concurrent.ExecutorService;

/**
 * @author github.kloping
 */
@WebFilter(filterName = "redirectFilter", urlPatterns = "/*")
@Slf4j
public class RedirectFilter implements Filter, ResultU {

    public static final SimpleDateFormat SF_0 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    public static final String ADMIN = "/admin";

    @Autowired
    IVisitorService visitorService;

    @Autowired
    ExecutorService executorService;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            executorService.submit(() -> {
                synchronized (RedirectFilter.class) {
                    HttpServletRequest request = (HttpServletRequest) servletRequest;
                    HttpServletResponse response = (HttpServletResponse) servletResponse;
                    String refer = request.getHeader("referer");
                    if (refer == null) {
                        refer = request.getHeader("Referer");
                    }
                    String rurl = request.getRequestURL().toString();
                    String ip = request.getHeader("x-real-ip");
                    if (ip == null) ip = request.getHeader("x-forwarded-for");
                    if (ip == null) ip = request.getRemoteAddr();
                    ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
                    Visitor visitor = new Visitor()
                            .setAgent(getOsName(request))
                            .setIp(ip)
                            .setUrl(rurl)
                            .setRefer(refer == null ? "" : refer);
                    Visitor vv = visitorService.lambdaQuery(visitor).one();
                    if (vv == null) {
                        visitor.setTimes(1);
                        visitor.setTime(SF_0.format(new Date()));
                        visitorService.save(visitor);
                    } else {
                        vv.setTimes(vv.getTimes() + 1);
                        vv.setTime(SF_0.format(new Date()));
                        visitorService.lambdaUpdate()
                                .eq(Visitor::getIp, ip)
                                .eq(Visitor::getAgent, visitor.getAgent())
                                .eq(Visitor::getUrl, rurl)
                                .eq(Visitor::getRefer, refer)
                                .set(Visitor::getTimes, vv.getTimes())
                                .set(Visitor::getTime, vv.getTime()).update();
                    }
                }
            });
        } finally {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
    }

    public static final String WINDOWS = "Windows";
    public static final String MAC = "Mac";
    public static final String UNIX = "Unix";
    public static final String ANDROID = "Android";
    public static final String IPHONE = "IPhone";
    public static final String UNKNOWN = "UnKnown";

    public static String getOsName(HttpServletRequest request) {
        String browserDetails = request.getHeader("User-Agent");
        String userAgent = browserDetails;
        if (userAgent.toLowerCase().indexOf("windows") >= 0) {
            return WINDOWS;
        } else if (userAgent.toLowerCase().indexOf("iphone") >= 0) {
            return IPHONE;
        } else if (userAgent.toLowerCase().indexOf("android") >= 0) {
            return ANDROID;
        } else if (userAgent.toLowerCase().indexOf("mac") >= 0) {
            return MAC;
        } else if (userAgent.toLowerCase().indexOf("x11") >= 0) {
            return UNIX;
        } else {
            return "UnKnown, More-Info: " + userAgent;
        }
    }
}
